<!DOCTYPE html>
<html>

<head>
    <title>osm buildings demo</title>
    <script type="text/javascript" src="https://unpkg.com/dat.gui@0.7.6/build/dat.gui.min.js"></script>
    <link type="text/css" rel="stylesheet" href="https://unpkg.com/maptalks/dist/maptalks.css">
    <script type="text/javascript" src="https://unpkg.com/maptalks/dist/maptalks.js"></script>
    <script type="text/javascript" src="https://unpkg.com/three@0.138.0/build/three.min.js"></script>
    <script type="text/javascript" src="https://unpkg.com/maptalks.three@latest/dist/maptalks.three.js"></script>
    <script type="text/javascript" src="buildings.js"></script>
    <style>
        html,
        body {
            margin: 0px;
            height: 100%;
            width: 100%;
        }

        #map {
            width: 100%;
            height: 100%;
            background-color: #000;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script>

        var map = new maptalks.Map("map", {
            center: [13.414049129456203, 52.53160987202452],
            zoom: 17,
            pitch: 70,
            bearing: 180,

            centerCross: true,
            doubleClickZoom: false,
            baseLayer: new maptalks.TileLayer('tile', {
                urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
                subdomains: ['a', 'b', 'c', 'd'],
                attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>'
            })
        });

        // features to draw
        var features = [];

        buildings.forEach(function (b) {
            features = features.concat(b.features);
        });

        // the ThreeLayer to draw buildings
        var threeLayer = new maptalks.ThreeLayer('t', {
            forceRenderOnMoving: true,
            forceRenderOnRotating: true
            // animation: true
        });

        var meshs = [];
        var material = getBuildingsMaterial();
        var topMaterial = new THREE.MeshPhongMaterial({ color: 'red', transparent: true, });
        // material.vertexColors = THREE.VertexColors;
        const topColor = new THREE.Color('red');

        threeLayer.prepareToDraw = function (gl, scene, camera) {
            var light = new THREE.DirectionalLight(0xffffff);
            light.position.set(0, -10, 10).normalize();
            scene.add(light);

            const ambientLight = new THREE.AmbientLight('#FFF', 0.5);
            scene.add(ambientLight);
            // camera.add(new THREE.PointLight('#fff', 2));

            var heightPerLevel = 10;
            var polygons = features.map(f => {
                const polygon = maptalks.GeoJSON.toGeometry(f);
                var levels = f.properties.levels || 1;
                polygon.setProperties({
                    height: heightPerLevel * levels,
                });
                return polygon;
            });



            const mesh = threeLayer.toExtrudePolygons(polygons, { interactive: false }, material);

            var polygons1 = polygons.map(p => {
                const p1 = p.copy();
                const height = p.getProperties().height;
                p1.setProperties({
                    height: 0.1,
                    bottomHeight: height
                });
                return p1;
            })
            const mesh1 = threeLayer.toExtrudePolygons(polygons1, { interactive: false, }, topMaterial);
            mesh1.isTop = true;

            // const bufferGeometry = mesh.getObject3d().geometry;
            // const geometry = new THREE.Geometry().fromBufferGeometry(bufferGeometry);
            //
            // const { vertices, faces, faceVertexUvs } = geometry;
            // for (let i = 0, len = faces.length; i < len; i++) {
            //     const { a, b, c } = faces[i];
            //     const p1 = vertices[a], p2 = vertices[b], p3 = vertices[c];
            //     //top face
            //     if (p1.z > 0 && p2.z > 0 && p3.z > 0) {
            //         const vertexColors = faces[i].vertexColors;
            //         for (let j = 0, len1 = vertexColors.length; j < len1; j++) {
            //             vertexColors[j].r = topColor.r;
            //             vertexColors[j].g = topColor.g;
            //             vertexColors[j].b = topColor.b;
            //         }
            //         const uvs = faceVertexUvs[0][i];
            //         for (let j = 0, len1 = uvs.length; j < len1; j++) {
            //             uvs[j].x = 0;
            //             uvs[j].y = 0;
            //         }
            //     }
            // }
            // mesh.getObject3d().geometry = new THREE.BufferGeometry().fromGeometry(geometry);
            // bufferGeometry.dispose();
            // geometry.dispose();

            // const position = bufferGeometry.attributes.position.array;
            // const uv =bufferGeometry.attributes.uv.array;
            // const color = bufferGeometry.attributes.color.array;
            // const index = mesh.getObject3d().geometry.index.array;
            // for (let i = 0, len = index.length; i < len; i += 3) {
            //     const a = index[i], b = index[i + 1], c = index[i + 2];
            //     const z1 = position[a * 3 + 2], z2 = position[b * 3 + 2], z3 = position[c * 3 + 2];
            //     // top vertex
            //     if (z1 > 0 && z2 > 0 && z3 > 0) {
            //         uv[a * 2] = 0;
            //         uv[a * 2 + 1] =  0;
            //         uv[b * 2] =  0;
            //         uv[b * 2 + 1] =  0;
            //         uv[c * 2] =  0;
            //         uv[c * 2 + 1] =  0;

            //         color[a * 3]=topColor.r;
            //         color[a * 3+1]=topColor.g;
            //         color[a * 3+2]=topColor.b;

            //         color[b * 3]=topColor.r;
            //         color[b * 3+1]=topColor.g;
            //         color[b * 3+2]=topColor.b;

            //         color[c * 3]=topColor.r;
            //         color[c * 3+1]=topColor.g;
            //         color[c * 3+2]=topColor.b;
            //     }



            // }
            meshs.push(mesh, mesh1);
            threeLayer.addMesh(meshs);
            initGui();
            animation();
        };
        threeLayer.addTo(map);


        function getBuildingsMaterial(color = 'red') {
            const texture = new THREE.TextureLoader().load('./data/a.png');
            texture.needsUpdate = true; //使用贴图时进行更新
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
            // texture.repeat.set(0.002, 0.002);
            texture.repeat.set(4, 10);
            const material = new THREE.MeshPhongMaterial({
                map: texture,
                transparent: true,
                color: '#fff'
            });
            return material;
        }

        function animation() {
            // layer animation support Skipping frames
            threeLayer._needsUpdate = !threeLayer._needsUpdate;
            if (threeLayer._needsUpdate) {
                threeLayer.redraw();
            }
            requestAnimationFrame(animation);
        }


        function initGui() {
            var params = {
                add: true,
                color: material.color.getStyle(),
                topColor: topMaterial.color.getStyle(),
                show: true,
                opacity: 1,
                altitude: 0,
                animateShow: animateShow
            };
            var gui = new dat.GUI();
            gui.add(params, 'add').onChange(function () {
                if (params.add) {
                    threeLayer.addMesh(meshs);
                } else {
                    threeLayer.removeMesh(meshs);
                }
            });
            gui.addColor(params, 'color').name('building color').onChange(function () {
                material.color.set(params.color);
                meshs.forEach(function (mesh) {
                    if (!mesh.isTop) {
                        mesh.setSymbol(material);
                    }
                });
            });
            gui.addColor(params, 'topColor').name('building top color').onChange(function () {
                topMaterial.color.set(params.topColor);
                // meshs.forEach(function (mesh) {
                //     if (!mesh.isTop) {
                //         mesh.setSymbol(material);
                //     }
                // });
            });
            gui.add(params, 'opacity', 0, 1).onChange(function () {
                material.opacity = params.opacity;
                topMaterial.opacity = params.opacity;
                meshs.forEach(function (mesh) {
                    if (!mesh.isTop) {
                        mesh.setSymbol(material);
                    }
                });
            });
            gui.add(params, 'altitude', 0, 300).onChange(function () {
                meshs.forEach(function (mesh) {
                    mesh.setAltitude(params.altitude);
                });
            });
            gui.add(params, 'animateShow');
        }

        function animateShow() {
            meshs.forEach(function (mesh) {
                mesh.animateShow({
                    duration: 3000
                });
            });
        }

    </script>
</body>

</html>